<template>
  <div class="app-container">
    <!-- 头部 -->
    <div class="app-header">
      <div class="title">
        <span>3D.Code</span>
      </div>
      <div class="actions">
        <button class="action-btn" @click="importCode" title="导入代码">
          <span>导入</span>
        </button>
        <button class="action-btn" @click="saveCode" title="保存代码">
          <span>保存</span>
        </button>
      </div>
    </div>

    <!-- 文件选项卡 -->
    <div class="file-tabs">
      <div
        v-for="tab in tabs"
        :key="tab.value"
        :class="['file-tab', { active: currentTab === tab.value }]"
        @click="switchTab(tab.value)"
      >
        <span
          :class="['file-icon', tab.value.includes('vue') ? '3d' : tab.value]"
        ></span>
        <span class="file-name">{{ tab.label }}</span>
      </div>
    </div>

    <!-- 内容 -->
    <div class="app-content">
      <div class="left">
        <CodeBox
          :code="getCurrentCode()"
          :language="getCurrentLanguage()"
          :line="line"
          @update:code="updateCode"
        />
      </div>
      <div class="right">
        <PreviewBox
          :htmlCode="getPreviewHtml()"
          :cssCode="getPreviewCss()"
          :jsCode="getPreviewJs()"
          :timestamp="codeData.timestamp"
        />
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, onMounted, computed, nextTick } from "vue";
import CodeBox from "./components/codeBox.vue";
import PreviewBox from "./components/previewBox.vue";

// 默认代码模板
const defaultHtml = `<div class="container">
  <h1>ECharts数据可视化示例</h1>
  <p>这是一个简单的ECharts图表演示</p>
  
  <div class="chart-section">
    <div id="chart-container" style="width: 100%; height: 400px;"></div>
  </div>
</div>`;

const defaultCss = `body {
  font-family: Arial, sans-serif;
  margin: 0;
  padding: 20px;
  background-color: #f5f5f5;
  color: #333;
}

.container {
  max-width: 800px;
  margin: 0 auto;
  background-color: white;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}

h1 {
  color: #333;
  border-bottom: 2px solid #4CAF50;
  padding-bottom: 10px;
}

.chart-section {
  margin-top: 20px;
  padding: 15px;
  border: 1px solid #ddd;
  border-radius: 4px;
  background-color: #f9f9f9;
  transition: box-shadow 0.3s;
}

.chart-section:hover {
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}`;

const defaultJs = `// 有多种方式导入第三方库：

// 方式1：使用标准 ES 模块导入语法 (推荐)
import * as echarts from 'echarts';

// 方式2：使用简化导入语法
// import dayjs from 'dayjs';

// 注意：所有importmap中定义的模块都可以被导入
// 可用的模块包括：vue, react, react-dom, lodash, three, axios, dayjs, echarts等

// 初始化ECharts实例
const initChart = () => {
  // 初始化ECharts实例
  const chartDom = document.getElementById('chart-container');
  if (chartDom) {
    const myChart = echarts.init(chartDom);

    // 指定图表的配置项和数据
    const option = {
      title: {
        text: '月度销售与利润统计',
        subtext: '示例数据',
        left: 'center'
      },
      tooltip: {
        trigger: 'axis',
        axisPointer: {
          type: 'shadow'
        }
      },
      legend: {
        data: ['销量', '利润'],
        bottom: '0'
      },
      grid: {
        left: '3%',
        right: '4%',
        bottom: '10%',
        containLabel: true
      },
      xAxis: {
        type: 'category',
        data: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月']
      },
      yAxis: {
        type: 'value'
      },
      series: [
        {
          name: '销量',
          type: 'bar',
          data: [5, 20, 36, 10, 10, 20, 25, 30, 32, 40, 42, 36],
          color: '#4CAF50',
          itemStyle: {
            borderRadius: 5
          },
          emphasis: {
            itemStyle: {
              color: '#2E7D32'
            }
          }
        },
        {
          name: '利润',
          type: 'line',
          data: [10, 15, 25, 22, 30, 40, 38, 35, 30, 45, 48, 43],
          color: '#2196F3',
          smooth: true,
          symbol: 'circle',
          symbolSize: 8,
          lineStyle: {
            width: 3
          }
        }
      ]
    };

    // 使用配置项显示图表
    myChart.setOption(option);

    // 监听窗口调整大小事件
    window.addEventListener('resize', function() {
      myChart.resize();
    });
    
    // 在控制台输出echarts版本信息
    console.log('ECharts版本:', echarts.version);
  } else {
    console.error('未找到图表容器元素');
  }
};

// 如果DOM已加载完成，直接初始化图表
if (document.readyState === 'complete' || document.readyState === 'interactive') {
  console.log('DOM已就绪，直接初始化图表');
  initChart();
} else {
  // 否则等待DOM加载完成
  document.addEventListener('DOMContentLoaded', () => {
    console.log('DOMContentLoaded事件触发，初始化图表');
    initChart();
  });
}`;

// HelloWorld组件代码
const helloWorldTemplate = `<template>
  <div ref="boxRef" class="container"></div>
</template>`;

const helloWorldScript = `import {
  Scene,
  PerspectiveCamera,
  WebGLRenderer,
  BoxGeometry,
  MeshLambertMaterial,
  Mesh,
  PointLight,
  Color,
} from "three";
import { ref, onMounted, onUnmounted, nextTick } from "vue";

let boxRef = ref(null);
let scene, camera, renderer, mesh;
let animationFrameId;

onMounted(() => {
  // 使用nextTick确保DOM已完全渲染
  nextTick(() => {
    if (boxRef.value) {
      initThree();
      animate();
    } else {
      console.warn('DOM元素尚未就绪，延迟初始化');
      // 若DOM未就绪，延迟再次尝试初始化
      setTimeout(() => {
        if (boxRef.value) {
          initThree();
          animate();
        } else {
          console.error('DOM元素初始化失败');
        }
      }, 100);
    }
  });
});

onUnmounted(() => {
  cancelAnimationFrame(animationFrameId);
  if (renderer) {
    renderer.dispose();
  }
  window.removeEventListener("resize", onWindowResize);
});

// 初始化
const initThree = () => {
  scene = new Scene();

  // 创建几何体
  const geometry = new BoxGeometry(100, 100, 100);
  const material = new MeshLambertMaterial({
    color: new Color("orange"),
  });
  mesh = new Mesh(geometry, material);
  mesh.position.set(0, 0, 0);
  scene.add(mesh);

  // 创建光源
  const pointLight = new PointLight(0xffffff, 10000);
  pointLight.position.set(80, 80, 80);
  scene.add(pointLight);

  // 获取容器尺寸
  const container = boxRef.value;
  // 防御性编程：再次确认容器存在
  if (!container) {
    console.warn("容器元素未就绪，无法初始化Three.js场景");
    return;
  }
  
  const width = container.clientWidth || window.innerWidth;
  const height = container.clientHeight || window.innerHeight;

  // 创建相机
  camera = new PerspectiveCamera(60, width / height, 0.1, 1000);
  camera.position.set(200, 200, 200);
  camera.lookAt(0, 0, 0);

  // 创建渲染器
  renderer = new WebGLRenderer({
    alpha: true,
    antialias: true,
    powerPreference: "high-performance",
  });
  renderer.setSize(width, height);

  container.appendChild(renderer.domElement);

  window.addEventListener("resize", onWindowResize);
};

// 动画
const animate = () => {
  // 如果没有渲染器，说明初始化未完成，不执行动画
  if (!renderer) return;
  
  animationFrameId = requestAnimationFrame(animate);
  // 添加旋转效果
  if (mesh) {
    mesh.rotation.x += 0.01;
    mesh.rotation.y += 0.01;
  }
  renderer.render(scene, camera);
};

// 窗口大小变化时，更新相机和渲染器
const onWindowResize = () => {
  if (!boxRef.value) return;

  const container = boxRef.value;
  const width = container.clientWidth || window.innerWidth;
  const height = container.clientHeight || window.innerHeight;

  if (!camera || !renderer) return;

  camera.aspect = width / height;
  camera.updateProjectionMatrix();

  renderer.setSize(width, height);
};`;

const helloWorldStyle = `.container {
  width: 100%;
  height: 100%;
  overflow: hidden;
}`;

// 代码类型选项卡
const tabs = [
  { label: "index.html", value: "html" },
  { label: "main.js", value: "js" },
  { label: "style.css", value: "css" },
  { label: "3D示例 (模板)", value: "vue-template" },
  { label: "3D示例 (脚本)", value: "vue-script" },
  { label: "3D示例 (样式)", value: "vue-style" },
];

// 当前代码数据
const codeData = reactive({
  html: defaultHtml,
  css: defaultCss,
  js: defaultJs,
  "vue-template": helloWorldTemplate,
  "vue-script": helloWorldScript,
  "vue-style": helloWorldStyle,
  timestamp: 0,
});

// 当前激活的选项卡
const currentTab = ref("html");
const line = ref(0);

// 是否处于Vue模式
const isVueMode = computed(() => {
  return currentTab.value.startsWith("vue-");
});

// 切换选项卡
const switchTab = (tab) => {
  // 先更新当前标签
  currentTab.value = tab;

  // 延迟发送重置事件，确保内容已经开始更新
  setTimeout(() => {
    // 发送重置编辑状态事件
    const event = new CustomEvent("resetEditorState");
    document.dispatchEvent(event);

    // Vue模式下更新预览时间戳
    if (isVueMode.value) {
      codeData.timestamp = Date.now();
    }
  }, 50);
};

// 获取当前编辑的代码
const getCurrentCode = () => {
  return codeData[currentTab.value];
};

// 获取当前编辑的语言
const getCurrentLanguage = () => {
  const languageMap = {
    html: "html",
    css: "css",
    js: "javascript",
    "vue-template": "html",
    "vue-script": "javascript",
    "vue-style": "css",
  };
  return languageMap[currentTab.value];
};

// 更新代码
const updateCode = (newCode) => {
  codeData[currentTab.value] = newCode;
  if (isVueMode.value) {
    // Vue模式下实时更新预览
    codeData.timestamp = Date.now();
  }
};

// 导入代码
const importCode = () => {
  // 导入代码逻辑
  console.log("导入代码");
};

// 保存代码
const saveCode = () => {
  // 保存代码逻辑
  console.log("保存代码");
};

// 获取预览HTML代码
const getPreviewHtml = () => {
  if (isVueMode.value) {
    return `<div id="app"></div>`;
  }
  return codeData.html;
};

// 获取预览CSS代码
const getPreviewCss = () => {
  if (isVueMode.value) {
    return codeData["vue-style"];
  }
  return codeData.css;
};

// 获取预览JS代码
const getPreviewJs = () => {
  if (isVueMode.value) {
    // 注意：这里不需要额外的import语句，因为previewBox组件会处理模块加载
    // 我们只需要提供一个支持模块语法的Vue组件初始化代码
    return `// 创建Vue组件实现
import { createApp, ref } from 'vue';
import { Scene, PerspectiveCamera, WebGLRenderer, BoxGeometry, MeshLambertMaterial, Mesh, PointLight, Color } from 'three';

// 组件模板声明 - 解析自编辑器代码
const template = document.createElement('template');
template.innerHTML = \`${codeData["vue-template"].replace(/\`/g, "\\`")}\`;
const templateContent = template.content.firstElementChild.outerHTML;

// 创建Vue应用
createApp({
  template: templateContent,
  setup() {
    // === 组件脚本开始 ===
    const boxRef = ref(null);
    let scene, camera, renderer, mesh;
    let animationFrameId;
    
    function onMounted() {
      // 使用nextTick确保DOM已完全渲染
      setTimeout(() => {
        if (boxRef.value) {
          initThree();
          animate();
        } else {
          console.warn('DOM元素尚未就绪，延迟初始化');
          // 如果仍未就绪，再次尝试
          setTimeout(() => {
            if (boxRef.value) {
              initThree();
              animate();
            } else {
              console.error('DOM元素初始化失败');
            }
          }, 100);
        }
      }, 0);
    }
    
    function onUnmounted() {
      cancelAnimationFrame(animationFrameId);
      if (renderer) {
        renderer.dispose();
      }
      window.removeEventListener("resize", onWindowResize);
    }
    
    // 初始化
    const initThree = () => {
      scene = new Scene();
    
      // 创建几何体
      const geometry = new BoxGeometry(100, 100, 100);
      const material = new MeshLambertMaterial({
        color: new Color("orange"),
      });
      mesh = new Mesh(geometry, material);
      mesh.position.set(0, 0, 0);
      scene.add(mesh);
    
      // 创建光源
      const pointLight = new PointLight(0xffffff, 10000);
      pointLight.position.set(80, 80, 80);
      scene.add(pointLight);
    
      // 获取容器尺寸
      const container = boxRef.value;
      const width = container.clientWidth || window.innerWidth;
      const height = container.clientHeight || window.innerHeight;
    
      // 创建相机
      camera = new PerspectiveCamera(60, width / height, 0.1, 1000);
      camera.position.set(200, 200, 200);
      camera.lookAt(0, 0, 0);
    
      // 创建渲染器
      renderer = new WebGLRenderer({
        alpha: true,
        antialias: true,
        powerPreference: "high-performance",
      });
      renderer.setSize(width, height);
    
      container.appendChild(renderer.domElement);
    
      window.addEventListener("resize", onWindowResize);
    };
    
    // 动画
    const animate = () => {
      animationFrameId = requestAnimationFrame(animate);
      ${
        codeData["vue-script"].includes("mesh.rotation.x += 0.01")
          ? `mesh.rotation.x += 0.01;
      mesh.rotation.y += 0.01;`
          : `// 取消注释下面两行，使立方体旋转
      // mesh.rotation.x += 0.01
      // mesh.rotation.y += 0.01`
      }
      renderer.render(scene, camera);
    };
    
    // 窗口大小变化时，更新相机和渲染器
    const onWindowResize = () => {
      if (!boxRef.value) return;
    
      const container = boxRef.value;
      const width = container.clientWidth || window.innerWidth;
      const height = container.clientHeight || window.innerHeight;
    
      if (!camera || !renderer) return;
    
      camera.aspect = width / height;
      camera.updateProjectionMatrix();
    
      renderer.setSize(width, height);
    };
    // === 组件脚本结束 ===

    // Vue生命周期钩子
    onMounted();
    
    return {
      boxRef
    };
  }
}).mount('#app');
`;
  }
  return codeData.js;
};
</script>

<style scoped lang="scss">
.app-container {
  height: 100vh;
  width: 100%;
  background-color: #282c34;
  color: #f0f0f0;

  overflow: hidden;

  display: flex;
  flex-direction: column;
}

.app-header {
  z-index: 100;

  display: flex;
  align-items: center;
  justify-content: space-between;

  height: 50px;
  width: 100%;
  box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.5);
  padding: 0 20px;
  box-sizing: border-box;
  background: linear-gradient(90deg, #282c34 0%, #1a1d23 100%);
  position: relative;

  .title {
    font-family: "Consolas", "Monaco", "Courier New", monospace;
    font-size: 36px;
    font-weight: bold;
    background: linear-gradient(
      45deg,
      #61dafb 0%,
      #61dafb 25%,
      #ff6b6b 25%,
      #ff6b6b 50%,
      #4dabf7 50%,
      #4dabf7 75%,
      #20c997 75%,
      #20c997 100%
    );
    background-size: 400% 400%;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    animation: gradient 8s ease infinite;
    text-shadow: 0 0 10px rgba(255, 255, 255, 0.1);
    letter-spacing: 1px;
  }

  .actions {
    display: flex;
    gap: 10px;

    .action-btn {
      padding: 6px 10px;
      border-radius: 4px;
      border: none;
      background: #3a3f4b;
      color: #ddd;
      cursor: pointer;
      font-size: 14px;
      transition: all 0.2s;
      min-width: 80px;

      &:hover {
        background: #4c5161;
      }

      &.active {
        background: #0e639c;
        color: white;
      }
    }
  }
}

/* 文件选项卡样式 */
.file-tabs {
  display: flex;
  height: 32px;
  background-color: #1e1e1e;
  padding-left: 5px;
  overflow-x: auto;
  overflow-y: hidden;
  white-space: nowrap;
  box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1);
}

.file-tab {
  display: inline-flex;
  align-items: center;
  height: 32px;
  padding: 0 10px;
  background-color: #2d2d2d;
  border-right: 1px solid #1e1e1e;
  cursor: pointer;
  user-select: none;
  position: relative;
  font-size: 12px;
}

.file-tab:hover {
  background-color: #383838;
}

.file-tab.active {
  background-color: #1e1e1e;
  border-top: 1px solid #0e639c;
}

.file-icon {
  width: 16px;
  height: 16px;
  margin-right: 6px;
  display: inline-block;
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;

  &.html {
    background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23E44D26"><path d="M3.5,2.5h17c0.6,0,1,0.4,1,1v17c0,0.6-0.4,1-1,1h-17c-0.6,0-1-0.4-1-1v-17C2.5,2.9,2.9,2.5,3.5,2.5z M6.5,8.5v2h2.5v8h2v-8h2.5v-2H6.5z M18,10.5h-2.5v2H18v4h-2.5v2H20v-8H18V10.5z"/></svg>');
  }

  &.css {
    background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%231572B6"><path d="M3.5,2.5h17c0.6,0,1,0.4,1,1v17c0,0.6-0.4,1-1,1h-17c-0.6,0-1-0.4-1-1v-17C2.5,2.9,2.9,2.5,3.5,2.5z M12.5,13.5c0.7,0,1.2-0.3,1.5-0.7l1.2,1.2c-0.6,0.6-1.6,1-2.7,1c-2.1,0-3.5-1.4-3.5-3.5c0-2.1,1.4-3.5,3.5-3.5c1.1,0,2.1,0.4,2.7,1l-1.2,1.2c-0.3-0.4-0.8-0.7-1.5-0.7c-1.2,0-1.8,0.8-1.8,2s0.6,2,1.8,2z"/></svg>');
  }

  &.js {
    background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23F7DF1E"><path d="M3.5,2.5h17c0.6,0,1,0.4,1,1v17c0,0.6-0.4,1-1,1h-17c-0.6,0-1-0.4-1-1v-17C2.5,2.9,2.9,2.5,3.5,2.5z M13,15.5c0,1.9-1.1,2.8-2.9,2.8c-1.6,0-2.5-0.8-3-1.8l1.6-1c0.3,0.5,0.6,1,1.3,1c0.7,0,1-0.3,1-1.3V9.5h2V15.5z M17.9,18.3c-1.8,0-2.9-0.8-3.5-1.9l1.6-0.9c0.4,0.7,1,1.1,1.9,1.1c0.8,0,1.3-0.4,1.3-1c0-0.7-0.5-0.9-1.5-1.3l-0.5-0.2c-1.5-0.6-2.5-1.4-2.5-3.1c0-1.5,1.2-2.7,3-2.7c1.3,0,2.2,0.4,2.9,1.7l-1.6,1c-0.3-0.6-0.7-0.8-1.3-0.8c-0.6,0-1,0.4-1,0.9c0,0.6,0.4,0.9,1.3,1.2l0.5,0.2c1.8,0.7,2.7,1.5,2.7,3.2C20.3,17.1,19.2,18.3,17.9,18.3z"/></svg>');
  }

  &.\\3d {
    background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23FF5722"><path d="M12,2C6.48,2,2,6.48,2,12s4.48,10,10,10s10-4.48,10-10S17.52,2,12,2z M12,20c-4.41,0-8-3.59-8-8s3.59-8,8-8s8,3.59,8,8 S16.41,20,12,20z M8,14l2.5,2.5L13,14z M16,14l-2.5-2.5L11,14z M12,17l-3-3h6L12,17z M11,11V6h2v5l-2,0z"/></svg>');
  }
}

.file-name {
  color: #ccc;
}

.file-tab.active .file-name {
  color: #fff;
}

@keyframes gradient {
  0% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}

.app-content {
  height: calc(100% - 82px); /* 减去头部和选项卡高度 */
  width: 100%;

  display: flex;
  flex-direction: row;

  overflow: hidden;
}

.left {
  width: 50%;
  height: 100%;
  overflow: hidden;
  flex: 1;
  border-right: 1px solid #1e1e1e;
}

.right {
  width: 50%;
  height: 100%;
  flex: 1;
}

.fullscreen-content {
  width: 100%;
  height: 100%;
  background-color: #1e1e1e;
}
</style>
